using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Admin.NET.Application.Entity;
using Admin.NET.Application.Service.Electricity.Dto;
using Admin.NET.Application.Service.OpenApi.Dto;
using Admin.NET.Core;
using Admin.NET.Core.Service;
using Furion.DataEncryption;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;

namespace Admin.NET.Application.Service.OpenApi;

[ApiDescriptionSettings(new string[] { "开放接口" }, Name = "OpenApi", Order = 100)]
public class OpenApiService : IDynamicApiController
{
	private readonly SqlSugarRepository<SysUser> _sysUserRep;

	private readonly SqlSugarRepository<Building> _rep;

	private readonly IHttpContextAccessor _httpContextAccessor;

	public OpenApiService(SqlSugarRepository<Building> rep, SqlSugarRepository<SysUser> sysUserRep, IHttpContextAccessor httpContextAccessor)
	{
		_sysUserRep = sysUserRep;
		_rep = rep;
		_httpContextAccessor = httpContextAccessor;
	}

	/// <summary>
	/// 获取token
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/openapi/token")]
	[AllowAnonymous]
	public async Task<dynamic> Token(TokenDto input)
	{
		SysUser user = await _sysUserRep.AsQueryable().Includes((SysUser t) => t.SysOrg).ClearFilter()
			.FirstAsync((SysUser u) => u.Account.Equals(input.Account));
		if (user == null)
		{
			throw Oops.Oh(ErrorCodeEnum.D0009);
		}
		if (user.Status == StatusEnum.Disable)
		{
			throw Oops.Oh(ErrorCodeEnum.D1017);
		}
		SysTenant tenant = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysTenant>>().GetFirstAsync((SysTenant u) => (long?)u.Id == user.TenantId);
		if (tenant != null && tenant.Status == StatusEnum.Disable)
		{
			throw Oops.Oh(ErrorCodeEnum.Z1003);
		}
		if (user.AccountType != AccountTypeEnum.SuperAdmin && tenant.IsSubscribe && (!tenant.VolumeEnd.HasValue || tenant.VolumeEnd < DateTime.Now.Date || tenant.VolumeStart > DateTime.Now.Date))
		{
			throw Oops.Oh("当前账号不在服务期间，请联系管理员");
		}
		if (CryptogramUtil.CryptoType == CryptogramEnum.MD5.ToString())
		{
			if (!user.Password.Equals(MD5Encryption.Encrypt(input.Password)))
			{
				throw Oops.Oh(ErrorCodeEnum.D1000);
			}
		}
		else if (!CryptogramUtil.Decrypt(user.Password).Equals(input.Password))
		{
			throw Oops.Oh(ErrorCodeEnum.D1000);
		}
		return await CreateToken(user);
	}

	/// <summary>
	/// 左侧的树
	/// </summary>
	/// <param name="type">1代表仅区域，2代表需要房间,3包含电表</param>
	/// <returns></returns>
	[HttpGet("/openapi/room")]
	public async Task<dynamic> GetRoom()
	{
		List<Building> result = await (from u in _rep.AsQueryable()
			orderby u.CreateTime
			select u).ToListAsync();
		List<OpenApiRoomTree> root = (from w in result
			where w.Pid == 0
			select new OpenApiRoomTree
			{
				Name = w.Name,
				Id = w.Id,
				BuildingId = w.Id,
				Type = 0,
				Children = new List<OpenApiRoomTree>()
			}).ToList();
		List<Room> rooms = new List<Room>();
		List<ElectricMeter> electricMeters = new List<ElectricMeter>();
		if (root.Count > 0)
		{
			rooms = await _rep.Context.Queryable<Room>().ToListAsync();
		}
		List<long> ids = new List<long>();
		foreach (OpenApiRoomTree item in root)
		{
			MapChild3(item, result, ids, rooms, electricMeters);
		}
		return new OpenApiRoomDto
		{
			RoomTrees = root
		};
	}

	[HttpGet("/openapi/meter")]
	public async Task<dynamic> Page([FromQuery] ElectricMeteInput input)
	{
		ISugarQueryable<ElectricMeter> query = _rep.Context.Queryable<ElectricMeter>().WhereIF(!string.IsNullOrWhiteSpace(input.Name), (ElectricMeter u) => u.Name.Contains(input.Name.Trim())).WhereIF(!string.IsNullOrWhiteSpace(input.Sn), (ElectricMeter u) => u.Sn.Contains(input.Sn.Trim()))
			.WhereIF(input.SignalStatus.HasValue, (ElectricMeter u) => (int?)u.SignalStatus == input.SignalStatus)
			.WhereIF(input.GateStatus.HasValue, (ElectricMeter u) => (int?)u.GateStatus == input.GateStatus)
			.WhereIF(input.IssuedStatus.HasValue, (ElectricMeter u) => (int?)u.IssuedStatus == input.IssuedStatus)
			.WhereIF(input.BuildingId.HasValue, (ElectricMeter u) => u.BuildingId == input.BuildingId)
			.WhereIF(input.RoomId.HasValue, (ElectricMeter u) => u.RoomId == input.RoomId)
			.WhereIF(input.ProtocolType.HasValue, (ElectricMeter u) => (int?)u.ProtocolType == input.ProtocolType)
			.WhereIF(input.PriceRuleId.HasValue, (ElectricMeter u) => u.PriceRuleId == input.PriceRuleId)
			.WhereIF(input.IsPublicMeter.HasValue, (ElectricMeter u) => (bool?)u.IsPublicMeter == input.IsPublicMeter)
			.WhereIF(input.IsElectricityProtection.HasValue, (ElectricMeter u) => (bool?)u.IsElectricityProtection == input.IsElectricityProtection)
			.WhereIF(input.OwnerControl.HasValue, (ElectricMeter u) => (bool?)u.OwnerControl == input.OwnerControl)
			.WhereIF(input.IsSubsidy.HasValue, (ElectricMeter u) => (int?)u.IsSubsidy == input.IsSubsidy)
			.WhereIF(input.LabelId.HasValue, (ElectricMeter u) => u.LabelId == input.LabelId);
		var info = (from u in query
			select new
			{
				SignalStatus = u.SignalStatus,
				Sn = u.Sn,
				Name = u.Name,
				Multiplier = u.Multiplier,
				CombinedActiveSharpElectricEnergy = u.CombinedActiveSharpElectricEnergy,
				GateStatus = u.GateStatus,
				Addr = u.Addr,
				CollectorId = u.CollectorId,
				CombinedActiveFlatElectricEnergy = u.CombinedActiveFlatElectricEnergy,
				CombinedActivePeakElectricEnergy = u.CombinedActivePeakElectricEnergy,
				CombinedActiveTotalElectricEnergy = u.CombinedActiveTotalElectricEnergy,
				CombinedActiveValleyElectricEnergy = u.CombinedActiveValleyElectricEnergy,
				Id = u.Id,
				PriceRuleId = u.PriceRuleId,
				PriceName = from s4 in SqlFunc.Subqueryable<ElectricityPriceRule>()
					where (long?)s4.Id == u.PriceRuleId
					select s4.Name,
				ProtocolType = u.ProtocolType,
				RoomId = u.RoomId,
				LatestMeterReadingTime = u.LatestMeterReadingTime
			} into u
			orderby u.Sn descending
			select u).OrderBuilder(input);
		return await info.ToPagedListAsync(input.Page, input.PageSize);
	}

	[NonAction]
	private void MapChild3(OpenApiRoomTree item, List<Building> list, List<long> ids, List<Room> rooms, List<ElectricMeter> electricMeters)
	{
		if (ids.Contains(item.Id))
		{
			return;
		}
		ids.Add(item.Id);
		item.Children = new List<OpenApiRoomTree>();
		List<OpenApiRoomTree> children = (from w in list
			where w.Pid == item.Id
			select new OpenApiRoomTree
			{
				Name = w.Name,
				Id = w.Id,
				BuildingId = w.Id,
				Type = 0,
				Children = new List<OpenApiRoomTree>()
			}).ToList();
		if (children.Count > 0)
		{
			item.Children.AddRange(children);
			foreach (OpenApiRoomTree child in children)
			{
				MapChild3(child, list, ids, rooms, electricMeters);
			}
		}
		if (rooms.Count <= 0)
		{
			return;
		}
		List<OpenApiRoomTree> tmprooms = (from w in rooms
			where w.BuildingId == item.Id
			select w into s
			select new OpenApiRoomTree
			{
				Id = s.Id,
				Type = 1,
				BuildingId = s.BuildingId,
				Name = s.Name,
				Balance = s.Balance,
				Children = new List<OpenApiRoomTree>()
			}).ToList();
		if (tmprooms.Count <= 0)
		{
			return;
		}
		item.Children.AddRange(tmprooms);
		if (electricMeters.Count <= 0)
		{
			return;
		}
		foreach (OpenApiRoomTree room in tmprooms)
		{
			List<OpenApiRoomTree> tmpmeters = (from w in electricMeters
				where w.RoomId == room.Id
				select w into s
				select new OpenApiRoomTree
				{
					Id = s.Id,
					Type = 2,
					Name = s.Name,
					Children = new List<OpenApiRoomTree>()
				}).ToList();
			if (tmpmeters.Count > 0)
			{
				room.Children.AddRange(tmpmeters);
			}
		}
	}

	[NonAction]
	public async Task<LoginOutput> CreateToken(SysUser user)
	{
		string accessToken = JWTEncryption.Encrypt(expiredTime: 10000L, payload: new Dictionary<string, object>
		{
			{ "UserId", user.Id },
			{ "TenantId", user.TenantId },
			{ "Account", user.Account },
			{ "RealName", user.RealName },
			{ "AccountType", user.AccountType },
			{ "OrgId", user.OrgId },
			{
				"OrgName",
				user.SysOrg?.Name
			},
			{
				"OrgType",
				user.SysOrg?.Type
			}
		});
		int refreshTokenExpire = 20000;
		HttpContextExtensions.SetTokensOfResponseHeaders(refreshToken: JWTEncryption.GenerateRefreshToken(accessToken, refreshTokenExpire), httpContext: _httpContextAccessor.HttpContext, accessToken: accessToken);
		return new LoginOutput
		{
			AccessToken = accessToken
		};
	}
}
